/* iksemel (XML parser for Jabber)
** Copyright (C) 2000-2003 Gurer Ozen
** This code is free software; you can redistribute it and/or
** modify it under the terms of GNU Lesser General Public License.
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "base64.h"

static const char base64_charset[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";


char *base64_decode(const char *buf, size_t inlen, size_t * outlen)
{
	assert(buf && inlen && outlen);

	char *res, *save;
	char val;
	const char *foo; 
	const char *end;
	int index, padding = 0;

	save = res = calloc(1, inlen * 6 / 8 + 1);
	if (!save)
		return NULL;

	index = 0;
	end = buf + inlen;

	while (*buf && buf < end) {
		if (!(foo = strchr(base64_charset, *buf))) {
			foo = base64_charset;
			padding ++;
		}
		val = (int)(foo - base64_charset);
		buf++;
		switch (index) {
			case 0:
				*res |= val << 2;
				break;
			case 1:
				*res++ |= val >> 4;
				*res |= val << 4;
				break;
			case 2:
				*res++ |= val >> 2;
				*res |= val << 6;
				break;
			case 3:
				*res++ |= val;
				break;
		}
		index++;
		index %= 4;
	}
	*res = 0;
	*outlen = res - save - padding;

	return save;
}

char *base64_encode(const char *buf, size_t inlen, size_t * outlen)
{
	assert(buf && inlen && outlen);

	char *res, *save;
	int k, t;

	save = res = calloc(1, inlen * 8 / 6 + 4);
	if (!save) return NULL;

	//3bytes blocks
	for (k = 0; k < inlen/3; ++k) {
		*res++ = base64_charset[*buf >> 2];
		t = ((*buf & 0x03) << 4);
		buf++;
		*res++ = base64_charset[t | (*buf >> 4)];
		t = ((*buf & 0x0F) << 2);
		buf++;
		*res++ = base64_charset[t | (*buf >> 6)];
		*res++ = base64_charset[*buf++ & 0x3F];
	}

	//the left 1 or 2 bytes
	switch (inlen % 3) {
		case 2:
			*res++ = base64_charset[*buf >> 2];
			t =  ((*buf & 0x03) << 4);
			buf++;
			*res++ = base64_charset[t | (*buf >> 4)];
			*res++ = base64_charset[((*buf++ & 0x0F) << 2)];
			*res++ = '=';
			break;
		case 1:
			*res++ = base64_charset[*buf >> 2];
			*res++ = base64_charset[(*buf++ & 0x03) << 4];
			*res++ = '=';
			*res++ = '=';
			break;
	}
	*res = 0;
	*outlen = res - save;
	return save;
}

#ifdef BASE64_MAIN
#include <stdio.h>
//#define DUMP_STR	"hi, I'm dumped"
#define DUMP_STR	"\x00\x00"
int main()
{
	unsigned int len = 2;//strlen(DUMP_STR);
	char * en = base64_encode(DUMP_STR, len, &len);
	printf("%s %u:%u\n", en, len, strlen(en));
	char *de = base64_decode(en, len, &len);
	printf("%s %u:%u\n", de, len, strlen(de));
	free(en);
	free(de);
	return 0;
}
#endif

